<?php
/**
 * 部门服务层
 *
 * @author Claude Code
 * @since 2025-11-03
 */

namespace app\service;

use app\model\admin\Department;
use app\model\admin\User;
use think\facade\Db;
use think\exception\ValidateException;
use think\facade\Cache;

/**
 * 部门业务逻辑处理
 *
 * 主要职责：
 * 1. 部门数据的增删改查
 * 2. 部门树形结构管理
 * 3. 部门层级关系维护
 * 4. 部门员工统计
 * 5. 缓存管理
 */
class DepartmentService extends BaseService
{
    /**
     * 部门模型
     * @var Department
     */
    protected $departmentModel;

    /**
     * 用户模型
     * @var User
     */
    protected $userModel;

    /**
     * 缓存键前缀
     */
    protected const CACHE_PREFIX = 'department:';

    /**
     * 缓存过期时间
     */
    protected const CACHE_EXPIRE = 3600;

    /**
     * 构造函数
     */
    public function __construct()
    {
        $this->departmentModel = new Department();
        $this->userModel = new User();

        $this->setModel($this->departmentModel);
        $this->setCacheConfig(true, self::CACHE_PREFIX, self::CACHE_EXPIRE);
    }

    /**
     * 获取部门列表（树形结构）
     * @param array $params 查询参数
     * @param bool $needTree 是否返回树形结构
     * @param bool $useCache 是否使用缓存
     * @return array
     */
    public function getDepartmentList(array $params = [], bool $needTree = true, bool $useCache = true): array
    {
        $cacheKey = 'list:' . md5(serialize($params) . $needTree);

        if ($useCache) {
            $cached = $this->getCache($cacheKey);
            if ($cached !== null) {
                $this->logInfo('从缓存获取部门列表', ['params' => $params]);
                return $cached;
            }
        }

        // 查询所有启用的部门
        $query = Db::name('department')
            ->where('status', '>', 0);

        // 应用查询条件
        if (!empty($params['title'])) {
            $query->where('title', 'like', '%' . $params['title'] . '%');
        }

        if (isset($params['status']) && $params['status'] !== '') {
            $query->where('status', $params['status']);
        }

        if (isset($params['type']) && $params['type'] > 0) {
            $query->where('type', $params['type']);
        }

        // 按sort降序、id升序排列
        $query->order('sort desc, id asc');

        $list = $query->select()->toArray();

        // 处理部门数据
        $list = $this->processDepartmentData($list);

        $result = $needTree ? $this->generateTree($list) : $list;

        if ($useCache) {
            $this->setCache($cacheKey, $result);
        }

        $this->logInfo('获取部门列表成功', [
            'count' => count($list),
            'tree' => $needTree
        ]);

        return $result;
    }

    /**
     * 处理部门数据（添加关联信息）
     * @param array $departments 部门列表
     * @return array
     */
    protected function processDepartmentData(array $departments): array
    {
        foreach ($departments as &$dept) {
            // 获取部门负责人信息
            if (!empty($dept['leader_ids'])) {
                $adminIds = explode(',', $dept['leader_ids']);
                $adminNames = Db::name('admin')
                    ->where('id', 'in', $adminIds)
                    ->where('status', '>=', 0)
                    ->column('name');
                $dept['leader'] = implode(',', $adminNames);
            } else {
                $dept['leader'] = '';
            }

            // 统计部门员工数量
            $dept['user_count'] = Db::name('admin')
                ->where('did', $dept['id'])
                ->where('status', '>=', 0)
                ->count();

            // 统计子部门数量
            $dept['children_count'] = Db::name('department')
                ->where('pid', $dept['id'])
                ->where('status', '>', 0)
                ->count();
        }

        return $departments;
    }

    /**
     * 生成树形结构
     * @param array $flatArray 扁平数组
     * @param int $parentId 父节点ID
     * @return array
     */
    protected function generateTree(array $flatArray, int $parentId = 0): array
    {
        $tree = [];
        foreach ($flatArray as $item) {
            if ($item['pid'] == $parentId) {
                $node = $item;
                $node['children'] = $this->generateTree($flatArray, $item['id']);
                $tree[] = $node;
            }
        }
        return $tree;
    }

    /**
     * 获取部门详情
     * @param int $id 部门ID
     * @param bool $useCache 是否使用缓存
     * @return array|null
     */
    public function getDepartmentInfo(int $id, bool $useCache = true): ?array
    {
        if ($id <= 0) {
            return null;
        }

        $cacheKey = "info:{$id}";

        if ($useCache) {
            $cached = $this->getCache($cacheKey);
            if ($cached !== null) {
                return $cached;
            }
        }

        $department = Db::name('department')
            ->where('id', $id)
            ->where('status', '>', 0)
            ->find();

        if (!$department) {
            return null;
        }

        // 获取部门负责人信息
        if (!empty($department['leader_ids'])) {
            $adminIds = explode(',', $department['leader_ids']);
            $leaders = Db::name('admin')
                ->field('id, name, username')
                ->where('id', 'in', $adminIds)
                ->where('status', '>=', 0)
                ->select()
                ->toArray();
            $department['leaders'] = $leaders;
        } else {
            $department['leaders'] = [];
        }

        // 获取父部门信息
        if ($department['pid'] > 0) {
            $parentDept = Db::name('department')
                ->field('id, title')
                ->where('id', $department['pid'])
                ->where('status', '>', 0)
                ->find();
            $department['parent_name'] = $parentDept['title'] ?? '';
        } else {
            $department['parent_name'] = '顶级部门';
        }

        // 统计信息
        $department['user_count'] = Db::name('admin')
            ->where('did', $id)
            ->where('status', '>=', 0)
            ->count();

        $department['children_count'] = Db::name('department')
            ->where('pid', $id)
            ->where('status', '>', 0)
            ->count();

        if ($useCache) {
            $this->setCache($cacheKey, $department);
        }

        return $department;
    }

    /**
     * 创建部门
     * @param array $data 部门数据
     * @return int 部门ID
     * @throws ValidateException
     */
    public function createDepartment(array $data): int
    {
        // 数据验证
        $this->validateDepartmentData($data);

        // 检查父部门是否存在
        if (!empty($data['pid']) && $data['pid'] > 0) {
            $parentDept = $this->getDepartmentInfo($data['pid'], false);
            if (!$parentDept) {
                throw new ValidateException('父部门不存在');
            }
        }

        // 检查同级部门名称是否重复
        $existing = Db::name('department')
            ->where('title', $data['title'])
            ->where('pid', $data['pid'] ?? 0)
            ->where('status', '>', 0)
            ->find();

        if ($existing) {
            throw new ValidateException('同级部门下已存在相同名称的部门');
        }

        return $this->transaction(function () use ($data) {
            $departmentData = [
                'title' => $data['title'],
                'pid' => (int)($data['pid'] ?? 0),
                'leader_ids' => $data['leader_ids'] ?? '',
                'phone' => $data['phone'] ?? '',
                'sort' => (int)($data['sort'] ?? 0),
                'remark' => $data['remark'] ?? '',
                'type' => (int)($data['type'] ?? 1),
                'status' => (int)($data['status'] ?? 1),
                'create_time' => time(),
                'update_time' => time()
            ];

            $deptId = Db::name('department')->insertGetId($departmentData);

            // 清除相关缓存
            $this->clearDepartmentCache();

            $this->logInfo('创建部门成功', ['dept_id' => $deptId, 'title' => $data['title']]);

            return $deptId;
        });
    }

    /**
     * 更新部门
     * @param int $id 部门ID
     * @param array $data 部门数据
     * @return bool
     * @throws ValidateException
     */
    public function updateDepartment(int $id, array $data): bool
    {
        if ($id <= 0) {
            throw new ValidateException('部门ID不能为空');
        }

        // 检查部门是否存在
        $department = $this->getDepartmentInfo($id, false);
        if (!$department) {
            throw new ValidateException('部门不存在');
        }

        // 数据验证
        $this->validateDepartmentData($data, $id);

        // 检查父部门是否存在（如果是修改父部门）
        if (isset($data['pid']) && $data['pid'] != $department['pid']) {
            if ($data['pid'] == $id) {
                throw new ValidateException('上级部门不能是该部门本身');
            }

            if ($data['pid'] > 0) {
                $parentDept = $this->getDepartmentInfo($data['pid'], false);
                if (!$parentDept) {
                    throw new ValidateException('父部门不存在');
                }

                // 检查是否将父部门设置为自己的子部门
                $childDepartments = $this->getDepartmentChildren($id);
                if (in_array($data['pid'], $childDepartments)) {
                    throw new ValidateException('上级部门不能是该部门的子部门');
                }
            }
        }

        // 检查部门名称是否已存在（排除当前部门）
        if (isset($data['title'])) {
            $existing = Db::name('department')
                ->where('title', $data['title'])
                ->where('pid', $data['pid'] ?? $department['pid'])
                ->where('id', '<>', $id)
                ->where('status', '>', 0)
                ->find();

            if ($existing) {
                throw new ValidateException('同级部门下已存在相同名称的部门');
            }
        }

        return $this->transaction(function () use ($id, $data, $department) {
            $updateData = [
                'title' => $data['title'] ?? $department['title'],
                'pid' => (int)($data['pid'] ?? $department['pid']),
                'leader_ids' => $data['leader_ids'] ?? $department['leader_ids'],
                'phone' => $data['phone'] ?? $department['phone'],
                'sort' => (int)($data['sort'] ?? $department['sort']),
                'remark' => $data['remark'] ?? $department['remark'],
                'type' => (int)($data['type'] ?? $department['type']),
                'status' => (int)($data['status'] ?? $department['status']),
                'update_time' => time()
            ];

            $result = Db::name('department')->where('id', $id)->update($updateData) > 0;

            // 清除相关缓存
            $this->clearDepartmentCache();

            $this->logInfo('更新部门成功', ['dept_id' => $id]);

            return $result;
        });
    }

    /**
     * 删除部门（软删除）
     * @param int $id 部门ID
     * @return bool
     * @throws ValidateException
     */
    public function deleteDepartment(int $id): bool
    {
        if ($id <= 0) {
            throw new ValidateException('部门ID不能为空');
        }

        // 检查部门是否存在
        $department = $this->getDepartmentInfo($id, false);
        if (!$department) {
            throw new ValidateException('部门不存在');
        }

        // 检查是否有员工
        $userCount = Db::name('admin')
            ->where('did', $id)
            ->where('status', '>=', 0)
            ->count();

        if ($userCount > 0) {
            throw new ValidateException("该部门下有{$userCount}名员工，不能删除");
        }

        // 检查是否有子部门
        $childCount = Db::name('department')
            ->where('pid', $id)
            ->where('status', '>', 0)
            ->count();

        if ($childCount > 0) {
            throw new ValidateException("该部门下有{$childCount}个子部门，不能删除");
        }

        return $this->transaction(function () use ($id) {
            $result = Db::name('department')
                ->where('id', $id)
                ->update([
                    'status' => -1,
                    'update_time' => time()
                ]) > 0;

            // 清除相关缓存
            $this->clearDepartmentCache();

            $this->logInfo('删除部门成功', ['dept_id' => $id]);

            return $result;
        });
    }

    /**
     * 获取部门的所有子部门ID（递归）
     * @param int $departmentId 部门ID
     * @return array
     */
    public function getDepartmentChildren(int $departmentId): array
    {
        $children = [];
        $departments = Db::name('department')
            ->field('id, pid')
            ->where('status', '>', 0)
            ->select()
            ->toArray();

        $this->findChildren($departments, $departmentId, $children);

        return $children;
    }

    /**
     * 递归查找子部门
     * @param array $departments 所有部门
     * @param int $parentId 父部门ID
     * @param array &$children 子部门ID数组
     * @return void
     */
    private function findChildren(array $departments, int $parentId, array &$children): void
    {
        foreach ($departments as $department) {
            if ($department['pid'] == $parentId) {
                $children[] = $department['id'];
                $this->findChildren($departments, $department['id'], $children);
            }
        }
    }

    /**
     * 验证部门数据
     * @param array $data 数据
     * @param int|null $id 部门ID（更新时）
     * @return void
     * @throws ValidateException
     */
    protected function validateDepartmentData(array $data, ?int $id = null): void
    {
        if (empty($data['title'])) {
            throw new ValidateException('部门名称不能为空');
        }

        $titleLength = mb_strlen($data['title']);
        if ($titleLength < 2) {
            throw new ValidateException('部门名称不能少于2个字符');
        }

        if ($titleLength > 50) {
            throw new ValidateException('部门名称不能超过50个字符');
        }

        if (isset($data['sort']) && $data['sort'] < 0) {
            throw new ValidateException('排序值不能为负数');
        }
    }

    /**
     * 清除部门相关缓存
     * @return void
     */
    protected function clearDepartmentCache(): void
    {
        $this->clearCache('department');
    }

    /**
     * 获取启用的部门列表（用于下拉选择）
     * @param int $type 部门类型：0-全部，1-内部部门，2-外部律所
     * @return array
     */
    public function getActiveDepartments(int $type = 0): array
    {
        $cacheKey = "active:{$type}";

        $cached = $this->getCache($cacheKey);
        if ($cached !== null) {
            return $cached;
        }

        $where = [['status', '=', 1]];

        if ($type == 1) {
            $where[] = ['type', '=', 1];
        } elseif ($type == 2) {
            $where[] = ['type', '=', 2];
        }

        $list = Db::name('department')
            ->where($where)
            ->field('id, title, pid, type')
            ->order('sort desc, id asc')
            ->select()
            ->toArray();

        // 生成树形结构
        $tree = $this->generateTree($list);

        $this->setCache($cacheKey, $tree);

        return $tree;
    }

    /**
     * 批量更新部门状态
     * @param array $ids 部门ID数组
     * @param int $status 状态
     * @return int 更新数量
     */
    public function batchUpdateStatus(array $ids, int $status): int
    {
        if (empty($ids)) {
            return 0;
        }

        $updateCount = Db::name('department')
            ->where('id', 'in', $ids)
            ->update([
                'status' => $status,
                'update_time' => time()
            ]);

        if ($updateCount) {
            $this->clearDepartmentCache();
            $this->logInfo('批量更新部门状态成功', [
                'ids' => $ids,
                'status' => $status,
                'count' => $updateCount
            ]);
        }

        return $updateCount;
    }
}
